/*
jQuery grab
Ported from Jin.js::gestures
Created by Jussi Kalliokoski
Licensed under MIT License.
*/


(function($){
var	extend	= $.extend,
mousedown	= 'mousedown',
mousemove	= 'mousemove',
mouseup	= 'mouseup',
touchstart	= 'touchstart',
touchmove	= 'touchmove',
touchend	= 'touchend',
touchcancel	= 'touchcancel',
gesturestart	= 'gesturestart',
gesturechange	= 'gesturechange',
gestureend	= 'gestureend',
gesturecancel	= 'gesturecancel',
MozTouchDown	= 'MozTouchDown',
MozTouchMove	= 'MozTouchMove',
MozTouchUp	= 'MozTouchUp',
mousewheel	= 'mousewheel',
DOMMouseScroll	= 'DOMMouseScroll';


function unbind(elem, type, func){
var fnc, i;
for (i=0; i<bind._binds.length; i++){
if (bind._binds[i].elem === elem && bind._binds[i].type === type && bind._binds[i].func === func){
if (document.addEventListener){
elem.removeEventListener(type, bind._binds[i].fnc, false);
} else {
elem.detachEvent('on'+type, bind._binds[i].fnc);
}
bind._binds.splice(i--, 1);
}
}
}

function bind(elem, type, func, pass){
var fnc, i;
if (bind[type]){
return bind[type].bind(elem, type, func, pass);
}
fnc = function(e){
if (!e){ // Fix some ie bugs...
e = window.event;
}
if (!e.stopPropagation){
e.stopPropagation = function(){ this.cancelBubble = true; };
}
e.data = pass;
func.call(elem, e);
};
if (document.addEventListener){
elem.addEventListener(type, fnc, false);
} else {
elem.attachEvent('on' + type, fnc);
}
bind._binds.push({elem: elem, type: type, func: func, fnc: fnc});
}

function grab(elem, options)
{
var data = {
move: {x: 0, y: 0},
offset: {x: 0, y: 0},
position: {x: 0, y: 0},
start: {x: 0, y: 0},
affects: document.documentElement,
stopPropagation: false,
preventDefault: true,
touch: true // Implementation unfinished, and doesn't support multitouch
};
extend(data, options);
data.element = elem;
bind(elem, mousedown, mouseDown, data);
if (data.touch){
bind(elem, touchstart, touchStart, data);
}
}
function ungrab(elem){
unbind(elem, mousedown, mousedown);
}
function mouseDown(e){
e.data.position.x = e.pageX;
e.data.position.y = e.pageY;
e.data.start.x = e.pageX;
e.data.start.y = e.pageY;
e.data.event = e;
if (e.data.onstart && e.data.onstart.call(e.data.element, e.data)){
return;
}
if (e.preventDefault && e.data.preventDefault){
e.preventDefault();
}
if (e.stopPropagation && e.data.stopPropagation){
e.stopPropagation();
}
bind(e.data.affects, mousemove, mouseMove, e.data);
bind(e.data.affects, mouseup, mouseUp, e.data);
}
function mouseMove(e){
if (e.preventDefault && e.data.preventDefault){
e.preventDefault();
}
if (e.stopPropagation && e.data.preventDefault){
e.stopPropagation();
}
e.data.move.x = e.pageX - e.data.position.x;
e.data.move.y = e.pageY - e.data.position.y;
e.data.position.x = e.pageX;
e.data.position.y = e.pageY;
e.data.offset.x = e.pageX - e.data.start.x;
e.data.offset.y = e.pageY - e.data.start.y;
e.data.event = e;
if (e.data.onmove){
e.data.onmove.call(e.data.element, e.data);
}
}
function mouseUp(e){
if (e.preventDefault && e.data.preventDefault){
e.preventDefault();
}
if (e.stopPropagation && e.data.stopPropagation){
e.stopPropagation();
}
unbind(e.data.affects, mousemove, mouseMove);
unbind(e.data.affects, mouseup, mouseUp);
e.data.event = e;
if (e.data.onfinish){
e.data.onfinish.call(e.data.element, e.data);
}
}
function touchStart(e){
e.data.position.x = e.touches[0].pageX;
e.data.position.y = e.touches[0].pageY;
e.data.start.x = e.touches[0].pageX;
e.data.start.y = e.touches[0].pageY;
e.data.event = e;
if (e.data.onstart && e.data.onstart.call(e.data.element, e.data)){
return;
}
if (e.preventDefault && e.data.preventDefault){
e.preventDefault();
}
if (e.stopPropagation && e.data.stopPropagation){
e.stopPropagation();
}
bind(e.data.affects, touchmove, touchMove, e.data);
bind(e.data.affects, touchend, touchEnd, e.data);
}
function touchMove(e){
if (e.preventDefault && e.data.preventDefault){
e.preventDefault();
}
if (e.stopPropagation && e.data.stopPropagation){
e.stopPropagation();
}
e.data.move.x = e.touches[0].pageX - e.data.position.x;
e.data.move.y = e.touches[0].pageY - e.data.position.y;
e.data.position.x = e.touches[0].pageX;
e.data.position.y = e.touches[0].pageY;
e.data.offset.x = e.touches[0].pageX - e.data.start.x;
e.data.offset.y = e.touches[0].pageY - e.data.start.y;
e.data.event = e;
if (e.data.onmove){
e.data.onmove.call(e.data.elem, e.data);
}
}
function touchEnd(e){
if (e.preventDefault && e.data.preventDefault){
e.preventDefault();
}
if (e.stopPropagation && e.data.stopPropagation){
e.stopPropagation();
}
unbind(e.data.affects, touchmove, touchMove);
unbind(e.data.affects, touchend, touchEnd);
e.data.event = e;
if (e.data.onfinish){
e.data.onfinish.call(e.data.element, e.data);
}
}

bind._binds = [];

$.fn.grab = function(a, b){
return this.each(function(){
return grab(this, a, b);
});
};
$.fn.ungrab = function(a){
return this.each(function(){
return ungrab(this, a);
});
};
})(jQuery);